import fs from 'fs'
import path from 'path'
import { formatProps } from './formatProps.js'
import { removeInvalid, splitScript } from './common.js'
import { formatData } from './formatData.js'
import { formatEmits } from './formatEmits.js'
import { formatComputed } from './formatComputed.js'
import { formatWatch } from './formatWatch.js'
import { formatMethods } from './formatMethods.js'
import { formatCycle } from './formatCycle.js'
import { formatFilters } from './formatFilters.js'
import { formatMixin } from './formatMixin.js'
import { fileSavePath } from '../config/importOrigin.js'

let importSection = ''
export const getImportSection = () => importSection
export const setImportSection = (str) => {
  importSection = str
}
let emitFns = []
export const getEmitFns = () => emitFns
export const setEmitFns = (arr) => {
  emitFns = arr
}
let domList = []
export const getDomList = () => domList
export const setDomList = (arr) => {
  domList = arr
}
let hooks = []
export const getHooks = () => hooks
export const setHooks = (arr) => {
  hooks = arr
}
let curFilePath = ''
export const getCurFilePath = () => curFilePath
export const setCurFilePath = (path) => {
  curFilePath = path
}

const resetCommonVar = () => {
  importSection = ''
  emitFns = []
  domList = []
  hooks = []
  curFilePath = ''
}

export const formatVueFile = async (filePath) => {
  resetCommonVar()
  const vueFile = fs.readFileSync(filePath, 'utf-8')
  const isVue3File = vueFile.search(/<script\s?setup.*?>/g) >= 0
  if (isVue3File) return
  const pathPrefix = filePath.replace(/(.*?)(\/|\\)(\w+)\.vue$/, '$1')
  const fileName = filePath.replace(/(.*?)(\/|\\)(\w+)\.vue$/, '$3')
  setCurFilePath(filePath)
  const htmlSection = vueFile.match(/<template>(.+\n|\n)*?<\/template>/g)[0]
  const scriptSection = vueFile.match(/<script>(.+\n|\n)*?<\/script>/g)[0]
  const scssSection = vueFile.match(/<style.*?>(.+\n|\n)*?<\/style>/g)[0]
  setImportSection(
    scriptSection
      .match(/<script.*?>(.+\n|\n)+export default/g)?.[0]
      ?.replace('<script>', '')
      .replace('export default', ''),
  )
  const removedInvalidStr = removeInvalid(scriptSection)
  const { props, filters, mixin, data, methods, computed, watch, beforeCreate, created, beforeMount, mounted, beforeDestroy, destroyed } = splitScript(removedInvalidStr)

  const formattedFilters = formatFilters(filters)
  const formattedMixin = formatMixin(mixin)
  const formattedProps = formatProps(props)
  const formattedMethods = formatMethods(methods) //这里面会修改dataRef
  const formattedComputed = formatComputed(computed)
  const formattedWatch = formatWatch(watch)
  const formattedEmits = formatEmits(emitFns)
  const formattedMount = formatCycle({
    cycle1: beforeCreate,
    name1: 'beforeCreate',
    cycle2: created,
    name2: 'created',
    cycle3: beforeMount,
    name3: 'beforeMount',
    cycle4: mounted,
    name4: 'mounted',
    keyword: 'onMounted',
  })
  const formattedUnmount = formatCycle({ cycle1: beforeDestroy, name1: 'beforeDestroy', cycle2: destroyed, name2: 'destroyed', keyword: 'onUnmounted' })
  // beforeUpdate updated 后面再加上
  const formattedData = formatData(data) // 由于this.$refs需要创建ref,所以处理data要晚于处理methods
  const fileData = `${htmlSection}
    <script setup>
    ${importSection}
    ${formattedProps}
    ${formattedEmits}
    ${formattedMixin}
    ${formattedFilters}
    ${formattedData}
    ${formattedComputed}
    ${formattedMethods}
    ${formattedWatch}
    ${formattedMount}
    ${formattedUnmount}
    </script>
    ${scssSection}`

  if (fileSavePath) {
    if (!fs.existsSync(`${path.resolve()}/${fileSavePath}`)) {
      fs.mkdirSync(`${path.resolve()}/${fileSavePath}`)
    }
  }
  let formattedFilePath = ''
  if (!fileSavePath) {
    formattedFilePath = `${pathPrefix}/${fileName}-formatted.vue`
  } else if (fileSavePath === 'replace') {
    formattedFilePath = `${pathPrefix}/${fileName}.vue`
  } else {
    const prefix = pathPrefix.replace(path.resolve(), '')
    formattedFilePath = `${path.resolve()}/${fileSavePath}${prefix}/${fileName}.vue`
  }
  writeFile(formattedFilePath, fileData)
  resetCommonVar()
}

const writeFile = (filePath, data) => {
  ensureDir(path.dirname(filePath))
  fs.writeFileSync(filePath, data, 'utf-8')
}

const ensureDir = (dirPath) => {
  try {
    fs.mkdirSync(dirPath, { recursive: true })
  } catch (error) {
    if (error.code !== 'EEXIST') {
      throw error
    }
  }
}
